package com.zoe.onelink.mybatis.autoconfigure;


import cn.hutool.core.util.ArrayUtil;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.zoe.onelink.common.entity.IBaseEntity;
import com.zoe.onelink.mybatis.handler.CommonMetaHandler;
import com.zoe.onelink.mybatis.injector.OnelinkMybatisMethodInjector;
import com.zoe.onelink.mybatis.interceptor.MybatisEntityUpdateInterceptor;
import com.zoe.onelink.mybatis.interceptor.impl.MybatisEntityUpdateInterceptorDispatcher;
import com.zoe.onelink.mybatis.interceptor.impl.MybatisModifiableCollResultInterceptor;
import com.zoe.onelink.mybatis.interceptor.impl.MybatisPreUpdateUpdateInterceptor;
import com.zoe.onelink.mybatis.interceptor.impl.MybatisQueryLimitInterceptor;
import com.zoe.onelink.mybatis.interceptor.impl.MybatisSpellFieldUpdateInterceptor;
import com.zoe.onelink.mybatis.properties.OnelinkMybatisPluginProperties;
import com.zoe.onelink.mybatis.provider.DefaultOperatorProvider;
import com.zoe.onelink.mybatis.provider.OperatorProvider;
import com.zoe.onelink.util.StrUtil;
import org.apache.ibatis.plugin.Interceptor;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

/**
 * <p>标题: </p>
 * <p>描述: </p>
 * <p>版权: Copyright (c) 2020</p>
 * <p>公司: 智业软件股份有限公司</p>
 *
 * @version: 1.0
 * @author: ruansheng
 * @date: 2020-10-13
 */
@SuppressWarnings("DefaultAnnotationParam")
@AutoConfigureBefore(MybatisPlusAutoConfiguration.class)
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({OnelinkMybatisPluginProperties.class})
public class OnelinkMybatisPlusAutoconfiguration {

    public OnelinkMybatisPlusAutoconfiguration(MybatisPlusProperties mybatisPlusProperties) {
        if (mybatisPlusProperties.getTypeAliasesSuperType() == null) {
            mybatisPlusProperties.setTypeAliasesSuperType(IBaseEntity.class);
        }
        String[] mapperLocations = {"classpath*:/mappings/**/*.xml"};
        if (mybatisPlusProperties.getMapperLocations() == null) {
            mybatisPlusProperties.setMapperLocations(mapperLocations);
        } else {
            String[] newLocations = ArrayUtil.addAll(mybatisPlusProperties.getMapperLocations(), mapperLocations);
            mybatisPlusProperties.setMapperLocations(ArrayUtil.distinct(newLocations));
        }
    }

    @Bean
    @ConditionalOnProperty(prefix = OnelinkMybatisPluginProperties.PREFIX, name = "enable-pagination", matchIfMissing = true)
    public InnerInterceptor paginationInnerInterceptor(DataSourceProperties dataSourceProperties) {
        // 先只做MYSQL和ORACLE判断
        DbType dbType = StrUtil.containsIgnoreCase(dataSourceProperties.getDriverClassName(), "mysql") ? DbType.MYSQL : DbType.ORACLE_12C;
        return new PaginationInnerInterceptor(dbType);
    }

    /**
     * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
     */
    @Bean
    @ConditionalOnProperty(prefix = OnelinkMybatisPluginProperties.PREFIX, name = "enable-pagination", matchIfMissing = true)
    @ConditionalOnMissingBean(MybatisPlusInterceptor.class)
    public MybatisPlusInterceptor mybatisPlusInterceptor(List<InnerInterceptor> interceptors) {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.setInterceptors(interceptors);
        return mybatisPlusInterceptor;
    }

    @Bean
    public Interceptor mybatisEntityUpdateInterceptorDispatcher(List<MybatisEntityUpdateInterceptor> mybatisEntityUpdateInterceptors) {
        return new MybatisEntityUpdateInterceptorDispatcher(mybatisEntityUpdateInterceptors);
    }

    @Bean
    @ConditionalOnProperty(prefix = OnelinkMybatisPluginProperties.PREFIX, name = "enable-auto-fill-meta-field", matchIfMissing = false)
    @ConditionalOnMissingBean(MetaObjectHandler.class)
    public MetaObjectHandler metaObjectHandler(OnelinkMybatisPluginProperties onelinkMybatisProperties, OperatorProvider operatorProvider) {
        return new CommonMetaHandler(onelinkMybatisProperties, operatorProvider);
    }

    @Bean
    @ConditionalOnMissingBean(OperatorProvider.class)
    public OperatorProvider operatorProvider() {
        return new DefaultOperatorProvider();
    }


    @Bean
    @ConditionalOnProperty(prefix = OnelinkMybatisPluginProperties.PREFIX, name = "enable-pre-update", matchIfMissing = false)
    public MybatisEntityUpdateInterceptor mybatisPreUpdateInterceptor() {
        return new MybatisPreUpdateUpdateInterceptor();
    }

    @Bean
    @ConditionalOnProperty(prefix = OnelinkMybatisPluginProperties.PREFIX, name = "enable-spell-field", matchIfMissing = false)
    public MybatisEntityUpdateInterceptor mybatisSpellFieldInterceptor(OnelinkMybatisPluginProperties onelinkMybatisProperties) {
        return new MybatisSpellFieldUpdateInterceptor(onelinkMybatisProperties);
    }

    @Bean
    @ConditionalOnProperty(prefix = OnelinkMybatisPluginProperties.PREFIX, name = "enable-query-limit", matchIfMissing = false)
    public Interceptor mybatisQueryLimitInterceptor(OnelinkMybatisPluginProperties onelinkMybatisPluginProperties) {
        return new MybatisQueryLimitInterceptor(onelinkMybatisPluginProperties);
    }

    @Bean
    @ConditionalOnProperty(prefix = OnelinkMybatisPluginProperties.PREFIX, name = "enable-modifiable-coll-result", matchIfMissing = false)
    public Interceptor mybatisModifiableCollResultInterceptor() {
        return new MybatisModifiableCollResultInterceptor();
    }

    @Bean
    @ConditionalOnMissingBean(ISqlInjector.class)
    public ISqlInjector onelinkMybatisSqlInjector() {
        return new OnelinkMybatisMethodInjector();
    }

}
